﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Rhino_Mocks.Models;
using FluentValidation.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Core;
using System.Reflection;
using Autofac.Builder;

namespace Rhino_Mocks {
    public class MvcApplication : System.Web.HttpApplication {
        protected void RegisterDependencies()
        {
            var builder = new ContainerBuilder();
            builder.Register(c => (new HttpContextWrapper(HttpContext.Current) as HttpContextBase))
                .As<HttpContextBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Request)
                .As<HttpRequestBase>()
                .InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Response)
                .As<HttpResponseBase>()
                .InstancePerLifetimeScope();
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterSource(new SettingSource());
            var container = builder.Build();
            //set dependency resolver
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
        protected void Application_Start()
        {
            RegisterDependencies();
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            //fluent vadiation
            DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
            ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new ModelValidatorFactory()));
        }
    }

    public class SettingSource : IRegistrationSource {
        static readonly MethodInfo BuildMethod = typeof(SettingSource).GetMethod(
            "BuildRegistration",
            BindingFlags.Static | BindingFlags.NonPublic);
        public bool IsAdapterForIndividualComponents
        {
            get
            {
                return false;
            }
        }

        public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
        {
            var ts = service as TypedService;
            if (ts != null && typeof(ISetting).IsAssignableFrom(ts.ServiceType))
            {
                var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType);
                yield return (IComponentRegistration)buildMethod.Invoke(null, null);
            }
        }

        static IComponentRegistration BuildRegistration<TSettings>()
        {
            return RegistrationBuilder
                .ForDelegate((c, p) =>
                {
                    var settings = Activator.CreateInstance<TSettings>();
                    foreach (var prop in typeof(TSettings).GetProperties())
                    {
                        if (!prop.CanRead || !prop.CanWrite) continue;
                        prop.SetValue(settings, true, null);
                    }
                    return settings;
                })
                .InstancePerLifetimeScope()
                .CreateRegistration();
        }
    }
}
